package com.gdust.hzx.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.gdust.hzx.product.mapper.CategoryMapper;
import com.gdust.hzx.product.service.CategoryService;
import com.gdust.hzx.model.entity.product.Category;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * ClassName: CategoryServiceImpl
 * Package: com.gdust.hzx.product.service.impl
 * Description: 分类服务实现类，提供一级分类查询和树形分类查询功能。
 *
 * @Author syun
 * @Create 2024/12/25 20:12
 * @Version 1.0
 */
@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {
    // 注入 CategoryMapper，用于执行数据库操作
    @Autowired
    private CategoryMapper categoryMapper;

    // 注入 RedisTemplate，用于操作 Redis 缓存
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    /**
     * 查询所有一级分类
     * 思路：先查询Redis缓存，Redis缓存没有查询到则查询数据库，
     * 若数据库查询到，则将数据存放到Redis中，后续使用Redis缓存查询一级分类，提高效率。
     * 并设置缓存过期时间为 14 天。
     * @return
     */
    @Override
    public List<Category> selectOneCategory() {
        //1.查询Redis，是否有所有一级分类
        String categoryOneJson = redisTemplate.opsForValue().get("category:one");

        //2.如果Redis包含所有一级分类，则直接返回
        if (StringUtils.hasText(categoryOneJson)) {
            //将categoryOneJson的字符串格式转化为List<Category>格式，用于返回到控制层
            List<Category> existCategoryList = JSON.parseArray(categoryOneJson, Category.class);
            log.info("从Redis缓存中查询到了所有的一级分类数据");
            return existCategoryList;
        }

        //3.如果Redis没有所有一级分类，则查询数据库，把数据库查询内容返回，并把查询内容存储到Redis中
        List<Category> categoryList = categoryMapper.selectOneCategory();
        log.info("从数据库中查询到了所有的一级分类数据");

        // 4. 将查询结果存入 Redis 缓存，设置过期时间为 14 天
        redisTemplate.opsForValue().set(
                "category:one",// 缓存的键
                JSON.toJSONString(categoryList),// 将数据序列化为 JSON 字符串
                14,// 缓存有效期
                TimeUnit.DAYS // 时间单位为天
        );

        // 5. 返回数据库查询结果
        return categoryList;
    }

    /**
     * 查询所有分类，并以树形结构封装
     * 功能说明：
     * 查询所有分类信息，使用递归或流操作构建树形结构；
     * 以父分类 ID 为条件，逐层封装子分类。
     *
     * 使用 @Cacheable 注解：
     * - value：指定缓存的名称为 "category"；
     * - key：缓存键值固定为 "all"，用于存储树形分类结构。
     *
     * @return 树形封装的分类列表
     */
    @Cacheable(value = "category", key = "'all'")//使用Redis缓存管理器进行管理
    @Override
    public List<Category> findCategoryTree() {
        //1.查询所有分类，返回list集合
        List<Category> allCategoryList = categoryMapper.findAll();

        //2.遍历所有分类list集合，mysql查询通过条件parentId =0得到所有1级分类
        List<Category> oneCategoryList = allCategoryList.stream()
                .filter(item -> item.getParentId().longValue() == 0)
                .collect(Collectors.toList());


        //3.遍历所有一级分类list集合，条件判断为：id = parentId,进而得到一级分类下的二级分类
        oneCategoryList.forEach(oneCategory -> {
            List<Category> twoCategoryList = allCategoryList.stream()
                    .filter(item -> item.getParentId() == oneCategory.getId())
                    .collect(Collectors.toList());

            //3.1 将二级分类封装到一级分类中
            oneCategory.setChildren(twoCategoryList);


            //4. 遍历所有二级分类，条件判断： id = parentId,得到二级分类下的三级分类
            twoCategoryList.forEach(twoCategory->{
                List<Category> threeCategory = allCategoryList.stream()
                        .filter(item -> item.getParentId() == twoCategory.getId())
                        .collect(Collectors.toList());

                //4.1 将三级分类封装到二级分类里面
                twoCategory.setChildren(threeCategory);
            });

        });

        // 返回封装后的树形分类结构
        return oneCategoryList;
    }




}
